package com.game.framework.balance;

import com.game.framework.balance.model.ServerInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class PlayerServiceInstance {
	/**
	 * 缓存PlayerID对应的所有的服务的实例的id,最外层的key是userId，里面的Map的key是serviceId，value是serverId
	 */
	private Map<Long, Map<Integer, Integer>> serviceInstanceMap = new ConcurrentHashMap<>();

	private ApplicationContext applicationContext;
	private StringRedisTemplate redisTemplate;
	private BusinessServerService businessServerService;

	public PlayerServiceInstance(ApplicationContext context) {
		this.applicationContext = context;
		this.redisTemplate = this.applicationContext.getBean(StringRedisTemplate.class);
		this.businessServerService = this.applicationContext.getBean(BusinessServerService.class);
	}

	public Set<Integer> getAllServiceId() {
		return this.businessServerService.getAllServiceId();
	}

	public int selectServerId(Long userId, int serviceId,String namespace) {
		Map<Integer, Integer> instanceMap = this.serviceInstanceMap.get(userId);
		int serverId = 0;
		if (instanceMap != null) {// 如果在缓存中已存在，直接获取对应的serverId
			serverId = instanceMap.getOrDefault(serviceId, 0);
		} else {// 如果不存在，创建缓存对象
			instanceMap = new ConcurrentHashMap<>();
			this.serviceInstanceMap.put(userId, instanceMap);
		}
		if (serverId != 0) {
			if (!this.businessServerService.isEnableServer(serviceId, serverId)) {// 检测目前这个缓存的serverId的实例是否还有效，如果有效，直接返回
				serverId = 0;// 如果无效，设置为空，下面再重新获取
			}
		}
		if (serverId == 0) {// 重新获取一个新的服务实例serverId
			String key = this.getRedisKey(userId,namespace);// 从redis查找一下，是否已由别的服务计算好
			Object value = this.redisTemplate.opsForHash().get(key, String.valueOf(serviceId));
			boolean flag = true;
			if (value != null) {
				serverId = Integer.parseInt((String) value);
				flag = this.businessServerService.isEnableServer(serviceId, serverId);
				if (flag) {// 如果redis中已缓存且是有效的服务实例serverId，直接返回
					this.addLocalCache(userId, serviceId, serverId);
					return serverId;
				}
			}
			if (value == null || !flag) {// 如果Redis中没有缓存，或实例已失效，重新获取一个新的服务实例Id
				serverId = this.selectServerIdAndSaveRedis(userId, serviceId,namespace);
				this.addLocalCache(userId, serviceId, serverId);
				return serverId;
			}
		}
		return serverId;
	}

	private void addLocalCache(long userId, int serviceId, int serverId) {
		Map<Integer, Integer> instanceMap = this.serviceInstanceMap.get(userId);
		instanceMap.put(serviceId, serverId);// 添加到本地缓存
	}
	private String getRedisKey(Long userId,String namespace) {
		return "service_instance_" + namespace + "_" + userId;
	}
	private Integer selectServerIdAndSaveRedis(Long userId, Integer serviceId,String namespace) {
		ServerInfo serverInfo = this.businessServerService.selectServerInfo(serviceId, userId);
		if(serverInfo == null) {
			log.error("找不到游戏服务器信息,playerID:{},serviceID:{}",userId,serviceId);
			return 0;
		}
		Integer serverId = this.businessServerService.selectServerInfo(serviceId, userId).getServerId();
		try {
			String key = this.getRedisKey(userId,namespace);
			this.redisTemplate.opsForHash().put(key, String.valueOf(serviceId), String.valueOf(serverId));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return serverId;
	}
	
	public void remove(long userId) {
		this.serviceInstanceMap.remove(userId);
	}

}
